Completed
Pull Request — master (#99)
by Ruben de
59s
created

BlocktrailBitcoinService.getBatchUnspentOutputs   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
nc 2
dl 0
loc 24
rs 8.9713
nop 1
1
var BlocktrailSDK = require('../api_client');
2
var _ = require('lodash');
3
var q = require('q');
4
var async = require('async');
5
6
/**
7
 *
8
 * @param options
9
 * @constructor
10
 */
11
var BlocktrailBitcoinService = function(options) {
12
    this.defaultSettings = {
13
        apiKey:      null,
14
        apiSecret:   null,
15
        network:     'BTC',
16
        testnet:     false,
17
18
        retryLimit: 5,
19
        retryDelay:  20,
20
        paginationLimit: 200   //max records to return per page
21
    };
22
    this.settings = _.merge({}, this.defaultSettings, options);
23
    //normalise the network settings
24
    var networkSettings = this.normaliseNetwork(this.settings.network, this.settings.testnet);
25
    this.settings.network = networkSettings.network;
26
    this.settings.testnet = networkSettings.testnet;
27
28
    this.client = new BlocktrailSDK(this.settings);
29
};
30
31
BlocktrailBitcoinService.prototype.normaliseNetwork =  function(network, testnet) {
32
    switch (network.toLowerCase()) {
33
        case 'btc':
34
        case 'bitcoin':
35
            if (testnet) {
36
                return {network: "BTC", testnet: true};
37
            } else {
38
                return {network: "BTC", testnet: false};
39
            }
40
        break;
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
41
        case 'tbtc':
42
        case 'bitcoin-testnet':
43
            return {network: "BTC", testnet: true};
44
        case 'bcc':
45
            if (testnet) {
46
                return {network: "BCC", testnet: true};
47
            } else {
48
                return {network: "BCC", testnet: false};
49
            }
50
        break;
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
51
        case 'tbcc':
52
            return {network: "BCC", testnet: true};
53
        default:
54
            throw new Error("Unknown network " + network);
55
    }
56
};
57
58
BlocktrailBitcoinService.prototype.setPaginationLimit = function(limit) {
59
    this.settings.paginationLimit = limit;
60
};
61
62
BlocktrailBitcoinService.prototype.estimateFee = function() {
63
    var self = this;
64
65
    return self.client.feePerKB().then(function(r) {
66
        return Math.max(r['optimal'], r['min_relay_fee']);
67
    });
68
};
69
70
/**
71
 * gets unspent outputs for a batch of addresses, returning an array of outputs with hash, index,
72
 * value, and script pub hex mapped to each corresponding address
73
 *
74
 * @param {array} addresses array of addresses
75
 * @returns {q.Promise}     promise resolves with array of unspent outputs mapped to addresses as
76
 *                          { address: [{"hash": hash, "index": index, "value": value, "script_hex": scriptHex}]}
77
 */
78
BlocktrailBitcoinService.prototype.getBatchUnspentOutputs = function(addresses) {
79
    var self = this;
80
    var deferred = q.defer();
81
82
    var batchResults = {};  //utxos mapped to addresses
83
84
    async.forEachSeries(function(address, cb) {
85
        var page = 1;
86
        var results = null;
87
        var utxos = [];
88
89
        async.doWhilst(function(done) {
90
            //do
91
            var params = {
92
                page: page,
93
                limit: self.settings.paginationLimit
94
            };
95
            self.client.addressUnspentOutputs(address, params).then(function(results) {
96
                utxos = utxos.concat(results['data']);
97
                page++;
98
                done();
99
            }, function(err) {
100
                console.log('error happened:', err);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
101
                done(err);
102
            });
103
        }, function() {
104
            //while
105
            return results && results['data'].length > 0;
106
        }, function(err) {
107
            //all done
108
            if (err) {
109
                console.log("complete, but with errors", err.message);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
110
            }
111
112
            //reduce the returned data into the values we're interested in, and map to the relevant addresses
113
            utxos.forEach(function(utxo) {
114
                var address = utxo['address'];
115
116
                if (typeof batchResults[address] === "undefined") {
117
                    batchResults[address] = [];
118
                }
119
120
                batchResults[address].push({
121
                    'hash': utxo['hash'],
122
                    'index': utxo['index'],
123
                    'value': utxo['value'],
124
                    'script_hex': utxo['script_hex']
125
                });
126
            });
127
128
            cb();
129
        });
130
131
    }, addresses, function() {
132
        deferred.resolve(batchResults);
133
    });
134
135
    //get unspent outputs for the current chunk of addresses - required data: hash, index, value, and script hex,
136
    async.doWhilst(function(done) {
137
        //do
138
        var params = {
139
            page: page,
0 ignored issues
show
Bug introduced by
The variable page seems to be never declared. If this is a global, consider adding a /** global: page */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
140
            limit: self.settings.paginationLimit
141
        };
142
        self.client.batchAddressUnspentOutputs(addresses, params).then(function(results) {
143
            utxos = utxos.concat(results['data']);
0 ignored issues
show
Bug introduced by
The variable utxos seems to be never declared. If this is a global, consider adding a /** global: utxos */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable utxos seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.utxos.
Loading history...
144
            page++;
0 ignored issues
show
Bug introduced by
The variable page seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.page.
Loading history...
Bug introduced by
The variable page seems to be never declared. If this is a global, consider adding a /** global: page */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
145
            done();
146
        }, function(err) {
147
            console.log('error happened:', err);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
148
            done(err);
149
        });
150
    }, function() {
151
        //while
152
        return results && results['data'].length > 0;
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable results is declared in the current environment, consider using typeof results === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
153
    }, function(err) {
154
        //all done
155
        if (err) {
156
            console.log("complete, but with errors", err.message);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
157
        }
158
159
        var batchResults = {};  //utxos mapped to addresses
160
        //reduce the returned data into the values we're interested in, and map to the relevant addresses
161
        utxos.forEach(function(utxo) {
0 ignored issues
show
Bug introduced by
The variable utxos seems to be never declared. If this is a global, consider adding a /** global: utxos */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
162
            var address = utxo['address'];
163
164
            if (typeof batchResults[address] === "undefined") {
165
                batchResults[address] = [];
166
            }
167
168
            batchResults[address].push({
169
                'hash': utxo['hash'],
170
                'index': utxo['index'],
171
                'value': utxo['value'],
172
                'script_hex': utxo['script_hex']
173
            });
174
        });
175
        deferred.resolve(batchResults);
176
    });
177
178
    return deferred.promise;
179
};
180
181
/**
182
 * @param {array} addresses   array of addresses
183
 * @returns {q.Promise}
184
 */
185
BlocktrailBitcoinService.prototype.batchAddressHasTransactions = function(addresses) {
186
    var self = this;
187
188
    return self.client.batchAddressHasTransactions(addresses)
189
        .then(function(result) {
190
            return result.has_transactions;
191
        });
192
};
193
194
module.exports = BlocktrailBitcoinService;
195